package com.zzw.springboot.util;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.zzw.springboot.bean.SysUser;
import com.zzw.springboot.service.SysUserService;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 数据迁移工具
 * 用于迁移用户数据到ShardingSphere分片表
 */
@Component
@Slf4j
public class DataMigrationUtil {

    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Autowired
    private SysUserService userService;

    // 是否启用ShardingSphere分表标志，可通过配置文件控制
    private boolean enableSharding = true;

    /**
     * 检查分表是否已经创建
     */
    public boolean checkTablesCreated() {
        try {
            for (int i = 0; i < 8; i++) {
                String tableName = "sys_user_" + i;
                Integer count = jdbcTemplate.queryForObject(
                    "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = ?",
                    Integer.class,
                    tableName
                );

                if (count == null || count == 0) {
                    log.error("分表 {} 不存在，请先执行建表脚本", tableName);
                    return false;
                }
            }
            return true;
        } catch (Exception e) {
            log.error("检查分表时发生错误", e);
            return false;
        }
    }

    /**
     * 查询当前分表中记录总数
     */
    public long countShardingRecords() {
        long total = 0;
        try {
            for (int i = 0; i < 8; i++) {
                String tableName = "sys_user_" + i;
                Integer count = jdbcTemplate.queryForObject(
                    "SELECT COUNT(*) FROM " + tableName,
                    Integer.class
                );

                total += (count == null ? 0 : count);
            }
        } catch (Exception e) {
            log.error("统计分表记录时发生错误", e);
        }
        return total;
    }

    /**
     * 迁移数据到分片表
     * @param batchSize 每批处理的记录数
     * @return 返回迁移的记录总数
     */
    @Transactional(rollbackFor = Exception.class)
    public int migrateData(int batchSize) {
        if (!checkTablesCreated()) {
            return 0;
        }

        AtomicInteger migratedCount = new AtomicInteger(0);

        try {
            // 1. 查询sys_user表总记录数
            Integer totalCount = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM sys_user",
                Integer.class
            );

            if (totalCount == null || totalCount == 0) {
                log.info("原表无数据，无需迁移");
                return 0;
            }

            log.info("原表总记录数: {}", totalCount);

            // 2. 查询最大ID
            Integer maxId = jdbcTemplate.queryForObject(
                "SELECT COALESCE(MAX(id), 0) FROM sys_user",
                Integer.class
            );

            if (maxId == null) {
                maxId = 0;
            }

            // 3. 分批查询并插入
            for (int startId = 1; startId <= maxId; startId += batchSize) {
                int endId = Math.min(startId + batchSize - 1, maxId);
                log.info("迁移用户数据 ID {} 至 {}", startId, endId);

                // 查询一批数据
                List<Map<String, Object>> userBatch = jdbcTemplate.queryForList(
                    "SELECT id, username, password, email, mobile_phone, status, create_time, update_time, avatar, gender, nickname, " +
                            "real_name, dept_id, last_login_time, last_login_ip, is_deleted, remark FROM sys_user WHERE id BETWEEN ? AND ?",
                    startId, endId
                );

                if (userBatch.isEmpty()) {
                    continue;
                }

                // 转换并批量插入
                List<SysUser> users = new ArrayList<>(userBatch.size());

                for (Map<String, Object> row : userBatch) {
                    SysUser user = new SysUser();
                    user.setId((Integer) row.get("id"));
                    user.setUsername((String) row.get("username"));
                    user.setPassword((String) row.get("password"));
                    user.setEmail((String) row.get("email"));
                    user.setMobilePhone((String) row.get("mobile_phone"));
                    user.setStatus((boolean)row.get("status") ? 1 : 0);

                    if (row.get("create_time") != null) {
                        user.setCreateTime(new java.sql.Timestamp(((java.util.Date) row.get("create_time")).getTime()));
                    }

                    if (row.get("update_time") != null) {
                        user.setUpdateTime(new java.sql.Timestamp(((java.util.Date) row.get("update_time")).getTime()));
                    }

                    user.setAvatar((String) row.get("avatar"));
                    user.setGender((boolean) row.get("gender") ? 1 : 0);
                    user.setNickname((String) row.get("nickname"));
                    user.setRealName((String) row.get("real_name"));
                    user.setDeptId((Integer) row.get("dept_id"));

                    if (row.get("last_login_time") != null) {
                        user.setLastLoginTime(new java.sql.Timestamp(((java.util.Date) row.get("last_login_time")).getTime()));
                    }

                    user.setLastLoginIp((String) row.get("last_login_ip"));
                    user.setIsDeleted((boolean) row.get("is_deleted") ? 1 : 0);
                    user.setRemark((String) row.get("remark"));

                    users.add(user);
                }

                // 批量保存，ShardingSphere会自动路由到对应分片
                boolean success = userService.saveBatch(users);
                if (success) {
                    migratedCount.addAndGet(users.size());
                    log.info("成功迁移 {} 条记录，累计 {}", users.size(), migratedCount.get());
                } else {
                    log.error("批量插入失败");
                }
            }

            log.info("数据迁移完成，共迁移 {} 条记录", migratedCount.get());
            return migratedCount.get();

        } catch (Exception e) {
            log.error("数据迁移过程中发生错误", e);
            throw new RuntimeException("数据迁移失败: " + e.getMessage(), e);
        }
    }

    /**
     * 验证迁移数据的一致性
     * @return 返回验证结果，true表示数据一致
     */
    public boolean validateMigration() {
        try {
            // 1. 检查总记录数
            Integer originalCount = jdbcTemplate.queryForObject(
                "SELECT COUNT(*) FROM sys_user",
                Integer.class
            );

            long shardingCount = countShardingRecords();

            if (originalCount == null || originalCount != shardingCount) {
                log.error("数据一致性检查失败：原表记录数 {} 与分表记录数 {} 不一致",
                    originalCount, shardingCount);
                return false;
            }

            // 2. 抽样检查数据内容（随机抽取20条记录进行比较）
            List<Map<String, Object>> sampleUsers = jdbcTemplate.queryForList(
                "SELECT id, username, email FROM sys_user ORDER BY RAND() LIMIT 20"
            );

            for (Map<String, Object> sample : sampleUsers) {
                Integer id = (Integer) sample.get("id");
                String username = (String) sample.get("username");
                String email = (String) sample.get("email");

                // 通过ShardingSphere查询
                SysUser shardingUser = userService.getById(id);

                if (shardingUser == null) {
                    log.error("数据一致性检查失败：分表中未找到ID为 {} 的用户", id);
                    return false;
                }

                if (!username.equals(shardingUser.getUsername()) ||
                    (email != null && !email.equals(shardingUser.getEmail()))) {
                    log.error("数据一致性检查失败：用户 {} 的数据不一致", id);
                    return false;
                }
            }

            log.info("数据一致性校验通过");
            return true;

        } catch (Exception e) {
            log.error("验证数据迁移时发生错误", e);
            return false;
        }
    }


    /**
     * 设置是否启用ShardingSphere分表
     */
    @ApiOperation("设置是否启用分表")
    @PostMapping("/setShardingEnable")
    public Result setShardingEnable(@RequestParam boolean enable) {
        this.enableSharding = enable;
        return Result.success("设置成功，当前分表状态：" + (enable ? "启用" : "禁用"));
    }

    /**
     * 获取分表启用状态
     */
    @ApiOperation("获取分表状态")
    @GetMapping("/shardingStatus")
    public Result getShardingStatus() {
        Map<String, Object> result = new HashMap<>();
        result.put("enabled", this.enableSharding);
        return Result.success(result);
    }
}
